define(
    [ "common", "service", "application", "abstractObject", "layer" ],
    function($, serv, app) {
      var canvas_factor = 2;// 375
      app.setLogicViewWidth(1080);
      // canvas initialize end;
      function canvasInitialize(ctx) {
        ctx.textBaseline = "middle";// "top";
        ctx.shadowColor = "rgba(0,0,0,1)";
        ctx.shadowBlur = 0;
        ctx.shadowOffsetX = 0;
        ctx.shadowOffsetY = 0;
        /**
         * translate的简单调用.
         */
        ctx.t = function() {
          return this.translate.apply(this, arguments);
        }
        /**
         * 判断浏览器中的坐标{x,y}是否在矩形中.
         */
        ctx.isPointInRect = function(x, y, left, top, width, height) {
          // this.fillStyle="red"
          this.beginPath();
          this.rect(left, top, width, height);
          this.closePath();
          // this.fill();
          return this.isPointInPath(x * canvas_factor, y * canvas_factor);// *2
        }
        /**
         * 保持原比例绘制图片.
         */
        ctx.drawImageIn = function(img, x, y, w, h) {
          try {
            var imgw = img.width;
            var imgh = img.height;
            var rw = imgw / w;
            var rh = imgh / h;

            var showw, showh;
            if (rw >= rh) {
              showw = w;
              showh = imgh / rw;
            } else {
              showh = h;
              showw = imgw / rh;
            }
            this.drawImage(img, x + (w - showw) / 2, y + (h - showh) / 2,
                showw, showh);
          } catch (e) {
            console.log(e);
          }
        };

        /**
         * 画线.
         */
        ctx.drawLine = function(x0, y0, x1, y1) {
          this.beginPath();
          this.moveTo(x0, y0);
          this.lineTo(x1, y1);
          this.closePath();
          this.stroke();
        }

        /**
         * 在save-restore结构中间执行方法.
         */
        ctx.render = function(funcRender) {
          try {
            this.save();
            if ($.isFunction(funcRender)) {
              try {
                funcRender.apply(this);
              } catch (e) {
                console.log(e);
              }
            }
            this.restore();
          } catch (e) {
            console.log(e);
          }
        };

        /**
         * 圆角矩形
         */
        ctx.roundRect = function(x, y, w, h, r) {
          if (w < 2 * r)
            r = w / 2;
          if (h < 2 * r)
            r = h / 2;
          this.beginPath();
          this.moveTo(x + r, y);
          this.arcTo(x + w, y, x + w, y + h, r);
          this.arcTo(x + w, y + h, x, y + h, r);
          this.arcTo(x, y + h, x, y, r);
          this.arcTo(x, y, x + w, y, r);
          this.closePath();
          return this;
        }

        /**
         * 画线
         */
        ctx.strokeLine = function(x, y) {
          this.beginPath();
          this.moveTo(0, 0);
          this.lineTo(x, y);
          this.closePath();
          this.stroke();
        }

        /**
         * 在指定的矩形区域中心.
         * 
         * @param image
         *          图片.
         * @param x
         *          区域左上定点x坐标.
         * @param y
         *          区域左上定点y坐标.
         * @param w
         *          区域宽度.
         * @param h
         *          区域高度.
         * @param isFillRect
         *          图片是否铺满整个矩形区域.
         *          <p>
         *          isFillRect为"true"的时候,参数"isFixedSize"不生效.
         *          </p>
         * @param isFixedSize
         *          图片是否按图片原大小显示.
         */
        ctx.drawImageInCenter = function(image, x, y, w, h, isFillRect,
            isFixedSize) {
          if (isEmpty(image)) {
            return;
          }
          var img_w = image.width;
          var img_h = image.height;
          var tw = (isFillRect ? w : (isFixedSize ? img_w : (w < h ? w : (img_w
              * h / img_h))));
          var th = (isFillRect ? h : (isFixedSize ? img_h : (h < w ? h : (img_h
              * w / img_w))));
          this.drawImage(image, 0, 0, img_w, img_h, x + (w - tw) / 2, y
              + (h - th) / 2, tw, th);
        }

      }
      // cavas initialize end;

      /**
       * @param settings
       *          配置.
       * @param target
       *          直接的html对象.
       */
      function AbstractPage(settings, target) {
        $(target).trigger("_distory", {
          UUID : this.UUID
        });
        AbstractObject.call(this, settings, target);

        this.ctrlLayer = new Layer("ctrl");
        this.topLayers = [];
        this.mainLayers = [];

        this.addMainLayer(new Layer("main"));// this.mainLayers[0];
        this.mainLayer = this.mainLayers[0];
        this.addTopLayer(new Layer("top"));// this.mainLayers[0];
        this.topLayer = this.topLayers[0];

        if (settings) {
          this.settings = $.extend({
            pageIdx : 0,
            pageSize : 20
          }, this.settings, settings);
        }
        if (target) {
          this.target = target;
        }
        this.binds();
      }
      AbstractPage.prototype = new AbstractObject();
      AbstractPage.prototype.constructor = AbstractPage;

      AbstractPage.prototype.ctrlLayer = new Layer();
      AbstractPage.prototype.topLayers = [];
      AbstractPage.prototype.mainLayers = [];

      AbstractPage.prototype.nextPage = function() {
        this.settings.pageIdx += 1;
      }

      /**
       * 添加层到主显示层.
       */
      AbstractPage.prototype.addMainLayer = function(layer) {
        if (layer) {
          this.mainLayers.push(layer);
          if (!isBlank(layer.name)) {
            $(this.mainLayers).data(layer.name, layer)
          }
        }
      };

      /**
       * 添加层到主显示层.
       */
      AbstractPage.prototype.addTopLayer = function(layer) {
        if (layer) {
          this.topLayers.push(layer);
          if (!isBlank(layer.name)) {
            $(this.topLayers).data(layer.name, layer)
          }
        }
      };

      /**
       * 删除.
       */
      AbstractPage.prototype.removeMainLayer = function(layer) {
        if (layer) {
          var tmp = [];
          $(this.mainLayers).each(function() {
            if (this != layer) {
              tmp.push(this);
              if (this.name) {
                $(tmp).data(this.name, this);
              }
            }
          }).removeData();
          this.mainLayers = tmp;
        }
      };

      /**
       * 删除.
       */
      AbstractPage.prototype.removeMainLayerByName = function(name) {
        if (!isBlank(name)) {
          return this.removeMainLayer($(this.mainLayers).data(name));
        }
      };

      /**
       * 默认配置属性.
       */
      AbstractPage.prototype.settings = {};

      AbstractPage.prototype.ctx2d = null;

      AbstractPage.prototype.binds = function() {

        this.applySuperFunc(AbstractObject, "binds", arguments);
        var self = this;
        var $this = $(this);
        $this.unbind();
        $this.off();

        var $target = $(self.target).unbind();

        $target.on("display", function(ev, data) {
          $this.trigger("display", data);
        });
        $this.on("display", function() {
          self.onDisplay.apply(self, arguments)
        });
        $this.on("loadBizData", function() {
          self.onLoadBizData.apply(self, arguments)
        });
        $this.on("loadScrollData", function() {
          self.onLoadScrollData.apply(self, arguments)
        });
        $this.on("refreshScrollData", function() {
          self.onRefreshScrollData.apply(self, arguments)
        });
        $this.on("loadDataCompleted", function() {
          self.onLoadDataCompleted.apply(self, arguments)
        });

      }

      AbstractPage.prototype.onLoadBizData = function(ev, data) {
      };

      AbstractPage.prototype.whenLongTap = function(left, top, width, height,
          callback) {
        return this.when("longTap", left, top, width, height, callback)
      }

      AbstractPage.prototype.when = function(evetnType, left, top, width,
          height, callback) {
        var res = false;
        var data = app.findEvent(evetnType);
        if (data && !serv.isBlankStr(data) && this.ctx2d) {
          if (this.ctx2d
              .isPointInRect(data.x, data.y, left, top, width, height)
              && ((!app.ACTIVE_RECT) || this.ctx2d.isPointInRect(data.x,
                  data.y, app.ACTIVE_RECT.left, app.ACTIVE_RECT.top
                      + this.scrollOffset, app.ACTIVE_RECT.width,
                  app.ACTIVE_RECT.height))) {
            callback.event = data;
            callback && app.addCallback(callback);
            res = true;
          }
        }
        return res;
      }

      AbstractPage.prototype.whenClick = function(left, top, width, height,
          callback) {
        try {

          if (this._trigger_load_scroll) {
            return;
          }

          var res = undefined;
          var data = app.findBizClick();

          if (data
              && this.ctx2d
              && this.ctx2d.isPointInRect(data.x, data.y, left, top, width,
                  height)) {
            callback.event = data;
            if (callback) {
              res=app.addCallback(callback);
            }// addCallback(callback);
            //res = true;
          }
          return res;

        } catch (e) {
          console.log(e);
        }
      }

      AbstractPage.prototype.whenScrollMove = function(left, top, width,
          height, callback) {
        var res = false;
        var data = app.findEvent("scrollMove");
        // onsole.log(JSON.stringify(data));
        if (data && !serv.isBlankStr(data) && this.ctx2d) {
          // console.log(JSON.stringify(data));
          if (this.ctx2d.isPointInRect(data.start.x, data.start.y, left, top,
              width, height)) {
            callback.event = data;
            callback && app.addCallback(callback);
            res = true;
          }
        }
        return res;
      }

      AbstractPage.prototype.whenScroll = function(left, top, width, height,
          callback) {
        var res = false;
        var data = app.findEvent("scroll");
        if (data && !serv.isBlankStr(data) && this.ctx2d) {
           if (this.ctx2d.isPointInRect(data.startX, data.startY, left, top,
              width, height)) {
            callback.event = data;
            callback && app.addCallback(callback);
            res = true;
          }else{
            //console.log("hehe12")
          }
        }
        return res;
      }
      AbstractPage.prototype.whenScrollUp = function(left, top, width, height,
          callback) {
        var res = false;
        var data = app.findEvent("scrollUp");
        if (data && !serv.isBlankStr(data) && this.ctx2d) {
          if (this.ctx2d.isPointInRect(data.startX, data.startY, left, top,
              width, height)) {
            callback.event = data;
            callback && app.addCallback(callback);
            res = true;
          }
        }
        return res;
      }
      AbstractPage.prototype.whenScrollDown = function(left, top, width,
          height, callback) {
        var res = false;
        var data = app.findEvent("scrollDown");
        if (data
            && !serv.isBlankStr(data)
            && this.ctx2d
            && this.ctx2d.isPointInRect(data.startX, data.startY, left, top,
                width, height)) {
          callback.event = data;
          callback && app.addCallback(callback);
          res = true;
        }
        return res;
      }
      AbstractPage.prototype.whenSwipe = function(left, top, width, height,
          callback) {
        var res = false;
        var data = app.findEvent("swipe");
        if (data
            && !serv.isBlankStr(data)
            && this.ctx2d
            && this.ctx2d.isPointInRect(data.startX, data.startY, left, top,
                width, height)) {
          callback.event = data;
          callback && app.addCallback(callback);
          res = true;
        }
        return res;
      }
      AbstractPage.prototype.whenSwipeLeft = function(left, top, width, height,
          callback) {
        var res = false;
        var data = app.findEvent("swipeLeft");
        if (data
            && !serv.isBlankStr(data)
            && this.ctx2d
            && this.ctx2d.isPointInRect(data.startX, data.startY, left, top,
                width, height)) {
          callback.event = data;
          callback && app.addCallback(callback);
          res = true;
        }
        return res;
      }
      AbstractPage.prototype.whenSwipeRight = function(left, top, width,
          height, callback) {
        var res = false;
        var data = app.findEvent("swipeRight");
        if (data
            && !serv.isBlankStr(data)
            && this.ctx2d
            && this.ctx2d.isPointInRect(data.startX, data.startY, left, top,
                width, height)) {
          callback.event = data;
          callback && app.addCallback(callback);
          res = true;
        }
        return res;
      }

      AbstractPage.prototype.onDisplay = function(ev, data) {
        try {
          ev.preventDefault();
          ev.stopPropagation();
          var $this = $(this);
          try {
            $this.trigger("loadData", data);
            $this.trigger("beforeRender", data);
            this.render(ev, data);
            $this.trigger("afterRender", data);
          } catch (e) {
            console.log(e);
          }
        } catch (e) {
          console.error(e);
        }
        return false;
      }
      AbstractPage.prototype.initCanvas = function() {
        try {
          var self = this;
          var $c = $(this.target);

          var w = $c.innerWidth(), h = $c.innerHeight();
          var _w = app.getLogicViewWidth();
          _w = (_w == -1 ? w : _w);
          var _h = _w * h / w;
          var scale = canvas_factor * w / _w;
          this.settings.canvas = {
            width : w,
            height : h,
            scale : scale,
            logicWidth : _w,
            logicHeight : _h
          };
          var rw = canvas_factor * w;
          var rh = canvas_factor * h;
          app.setLogicViewWidth(_w);
          app.setLogicViewHeight(_h);
          app.setPhysicalViewWidth(w);
          app.setPhysicalViewHeight(h);
          app.setRealViewWidth(rw);
          app.setRealViewHeight(rh);
          app.scale = scale;

          // alert(2);
          //console.log("fact:" + canvas_factor)
          //console.log("rw*rh:" + rw * rh);
          var $canvas = $("canvas");
          if ($canvas.length == 0) {
            $canvas = $("<canvas width='"
                + rw
                + "px' height='"
                + rh
                + "px' style='overflow: hidden;padding:0px;margin:0px;border:0px none white;background-color:#ffffff;width:"
                + w + "px;height:" + h + "px' />");
            $c.html($canvas);

            console.log(1)
            $canvas[0].getContext('2d').scale(scale, scale);
          }
          this.$canvas = $canvas;
          this.ctx2d = $canvas[0].getContext('2d');
          var c = this.ctx2d;

          canvasInitialize(c);

          $canvas.unbind();

          $canvas.on("tap", function(ev) {
            try {
              app.addEvent({
                reason : "tap",
                x : ev.originalEvent.pageX,
                y : ev.originalEvent.pageY
              });
            } catch (e) {
              console.log(e);
            }
          });
          

          $canvas.on("click", function(ev) {
            ev.preventDefault();
            ev.stopPropagation();
            try {
              app.addEvent({
                reason : "click",
                x : ev.originalEvent.pageX,
                y : ev.originalEvent.pageY
              });
            } catch (e) {
              console.log(e);
            }
            return false;
          });

          var scrollStart = null;
          var lastScroll = null;
          window.touchStartTm = -1;
          
          var getXY=function(ev,type){
            var x = 0;
            var y = 0;
            
            if(!type){
              type="mousedown";
            }
            
            if(type.toLowerCase()==event.type.toString().toLowerCase()){
              x=ev.pageX;
              y=ev.pageY;
            }else{
              x=ev.originalEvent.changedTouches[0].pageX;
              y = ev.originalEvent.changedTouches[0].pageY;
            }
            return {x:x,y:y}
          }

          var ap_on_touch_start = function(ev) {
            try {
              window.touchStartTm = new Date().getTime();
              
              var p=getXY(ev);
              var x= p.x;
              var y= p.y;
              
              scrollStart = {
                x : x,
                y : y,
                detaY : 0,
                stepY : 0,
                detaX : 0,
                stepX : 0,
                time : new Date().getTime(),
                detaTm : 0,
                stepTm : 0
              };
              lastScroll = scrollStart;
              app.addEvent($.extend({
                reason : "touchStart"
              }, scrollStart));

              app.addEvent($.extend({
                reason : "scrollStart"
              }, scrollStart));
              setTimeout(function() {
                if (window.touchStartTm > 0
                    && ((window.touchStartTm + 499) < new Date().getTime())) {
                  try {
                    app.addEvent($.extend({
                      reason : "longTap"
                    }, scrollStart));
                    // window.touchStartTm = -1;
                  } catch (e) {
                    console.log(e);
                  }
                }
              }, 500);
            } catch (e) {
              console.log(e);
            }
          };
          
          var ap_on_touch_move=function(ev) {
            try {
              ev.preventDefault();
              ev.stopPropagation();
              
              
              var p=getXY(ev,"mousemove");
              var x= p.x;
              var y= p.y;
              
              if(!scrollStart){
                return;
              }
              
              var long_time = new Date().getTime();
              var cur = {
                x : x,
                detaX : x - scrollStart ? scrollStart.x : 0,
                stepX : x - lastScroll.x,
                y : y,
                detaY : y - scrollStart ? scrollStart.y : 0,
                stepY : y - lastScroll.y,
                time : long_time,
                detaTm : scrollStart ? (long_time - scrollStart.time) : 0,
                stepTm : long_time - lastScroll.time,
                start : scrollStart ? scrollStart : undefined
              };
              app._lastTouchMove = cur;
              app.addEvent($.extend({
                reason : "scrollMove"
              }, cur));
              lastScroll = cur;
              return true;
            } catch (e) {
              console.log(e);
            }
          };
          
          var ap_on_touch_canel = function(ev) {
            touchStart = -1;
          };
          
          var ap_on_touch_end = function(ev) {
            try {
              touchStart = -1;
              var p=getXY(ev,"mouseup");
              var x= p.x;
              var y= p.y;
              var long_time = new Date().getTime();
              var cur = {
                x : x,
                detaX : x - scrollStart.x,
                stepX : x - lastScroll.x,
                y : y,
                detaY : y - scrollStart.y,
                stepY : y - lastScroll.y,
                time : long_time,
                detaTm : long_time - scrollStart.time,
                stepTm : long_time - lastScroll.time,
                start : scrollStart
              };
              app.addEvent($.extend({
                reason : "scrollEnd"
              }, cur));
              var _e = {
                startX : cur.start.x,
                startY : cur.start.y,
                stopX : cur.x,
                stopY : cur.y

                ,
                detaX : cur.x - cur.start.x,
                detaY : cur.y - cur.start.y,
                startTm : cur.start.time,
                stopTm : cur.time,
                detaTm : cur.time - cur.start.time,
                stepX : app._lastTouchMove ? app._lastTouchMove.stepX
                    : undefined,
                stepY : app._lastTouchMove ? app._lastTouchMove.stepY
                    : undefined,
                stepTm : app._lastTouchMove ? app._lastTouchMove.stepTm
                    : undefined
              };
              if (Math.abs(_e.detaY) >= Math.abs(_e.detaX)) {
                app.addEvent($.extend({
                  reason : "scroll"
                }, _e));
                if (_e.detaY > 10) {
                  app.addEvent($.extend({
                    reason : "scrollDown"
                  }, _e));
                } else if (_e.detaY < -10) {
                  app.addEvent($.extend({
                    reason : "scrollUp"
                  }, _e));
                }
              } else {
                app.addEvent($.extend({
                  reason : "swipe"
                }, _e));
                if (_e.detaX > 10) {
                  app.addEvent($.extend({
                    reason : "swipeRight"
                  }, _e));
                } else if (_e.detaX < -10) {
                  app.addEvent($.extend({
                    reason : "swipeLeft"
                  }, _e));
                }
              }

              lastScroll = null;
              scrollStart = null;
              app._lastTouchMove = null;
            } catch (e) {
              console.log(e);
            }
          };
          
          $canvas.on("touchstart", ap_on_touch_start);
          $canvas.on("mousedown", ap_on_touch_start);
          $canvas.on("touchmove", ap_on_touch_move);
          $canvas.on("mousemove", ap_on_touch_move);
          $canvas.on("touchcanel", ap_on_touch_canel);
          $canvas.on("mouseout", ap_on_touch_canel);
          $canvas.on("touchend", ap_on_touch_end);
          $canvas.on("mouseup", ap_on_touch_end);
        } catch (e) {
          console.log(e)
        }
      }

      // 滚动屏幕的处理 开始.

      AbstractPage.prototype.scrollOffset = 0;
      AbstractPage.prototype.scrollFly = 0;
      AbstractPage.prototype.scrollFlyOffset = 0;
      /**
       * 判断是否需要加载更多记录的内部标识.
       * <p>
       * </p>
       */
      AbstractPage.prototype._trigger_load_scroll = false;

      AbstractPage.prototype.handleScroll = function(c, top, left, width,
          height, ch) {
        try {
          if (ch < height) {
            return;
          }

          var self = this;
          app.ACTIVE_RECT = {
            top : top,
            left : left,
            width : width,
            height : height
          };

          c.beginPath();
          c.rect(app.ACTIVE_RECT.left, app.ACTIVE_RECT.top,
              app.ACTIVE_RECT.width, app.ACTIVE_RECT.height);
          c.closePath();
          c.clip();
          c.fillStyle = "#F0F0F0";
          //
          self.when("touchStart", app.ACTIVE_RECT.left, app.ACTIVE_RECT.top,
              app.ACTIVE_RECT.width, app.ACTIVE_RECT.height, function(ev) {
                if (self.scrollFly != 0) {
                  self.scrollFly = 0;
                  self.scrollFlyOffset = 0;
                }
              });

          self.when("scrollStart", app.ACTIVE_RECT.left, app.ACTIVE_RECT.top,
              app.ACTIVE_RECT.width, app.ACTIVE_RECT.height, function(ev) {
                if (self.scrollFly != 0) {
                  self.scrollFly = 0;
                  self.scrollFlyOffset = 0;
                }
              });

          self.whenScroll(app.ACTIVE_RECT.left, app.ACTIVE_RECT.top,
              app.ACTIVE_RECT.width, app.ACTIVE_RECT.height, function(ev) {
                if (ev.stepY != 0 && ev.stepTm < 50) {
                  self.scrollFly += ev.stepY * 50;
                }
              });

          self.whenScrollMove(app.ACTIVE_RECT.left, app.ACTIVE_RECT.top,
              app.ACTIVE_RECT.width, app.ACTIVE_RECT.height, function(ev) {

                self.scrollOffset += ev.stepY;
                // 识别在顶端/低端的下拉或上托
                if (-1 == self.scrollType) {// 初始在记录列表下端，向上滚动 (逆向滚动)
                } else {// 初始在记录列表上端，向下滚动 (正向滚动)
                  if (!self._trigger_load_scroll) {
                    if (self.scrollOffset > 0) {
                      $(self).trigger("refreshScrollData");
                    } else {
                      // self._trigger_load_scroll = false;
                    }
                  }
                }
              });

          if (Math.abs(self.scrollFly) > Math.abs(self.scrollFlyOffset)) {
            var mv = (self.scrollFly - self.scrollFlyOffset) / 50;
            self.scrollFlyOffset += mv;
            self.scrollOffset += mv;
            if ((Math.abs(self.scrollFly) - Math.abs(self.scrollFlyOffset)) < 30) {
              self.scrollFlyOffset = 0;
              self.scrollFly = 0;
            }
          } else {
            self.scrollOffset += self.scrollFlyOffset;
            self.scrollFly = 0;
            self.scrollFlyOffset = 0;
          }

          if (-1 == self.scrollType) {// 初始在记录列表下端，向上滚动 (逆向滚动)
            if (self.scrollOffset < 0) {
              self.scrollOffset = 0;
            }

            if (self.scrollOffset > (ch - height)) {
              self.scrollOffset = (ch - height);
            }
            c.t(0, self.scrollOffset);
          } else {// 初始在记录列表上端，向下滚动 (正向滚动)
            if (self.scrollOffset > 0) {
              self.scrollOffset = 0;
            }

            if (self.scrollOffset < -(ch - height)) {
              self.scrollOffset = -(ch - height);
              self.scrollFly = 0;
              self.scrollFlyOffset = 0;
              // 正向滚动时触发加载更多
              if (!self._trigger_load_scroll) {
                if (Math.abs(self.scrollOffset) == Math.abs(ch - height)) {
                  $(self).trigger("loadScrollData");
                } else {
                }
              }
            }

            c.t(0, self.scrollOffset);

          }
        } catch (e) {
          console.log(e);
        }
      }

      AbstractPage.prototype.clearScroll = function(c, top, left, width,
          height, ch) {
        app.ACTIVE_RECT = null;
        if (c) {
          try {
            var self = this;
            if (self.settings._trigger_load_scroll) {
              c.render(function() {
                c.fillStyle = "rgba(255,255,255,0.9)";
                c.beginPath();
                c.fillRect(left, top, width, height);
                var img = serv.loadImg("loading.gif");
                c.drawImage(img, left + (width - img.width) / 2, top
                    + (height - img.height) / 2);
                c.closePath();
              });
            }
          } catch (e) {
            console.log(e);
          }
        }
      }

      AbstractPage.prototype.renderScroll = function(c, top, left, width,
          height, ch, callback) {
        var self = this;
        try {
          c.render(function() {
            self.handleScroll(c, top, left, width, height, ch);
            callback.call(self);
          });
          self.clearScroll(c, top, left, width, height, ch);
        } catch (e) {
          console.log(e);
        }
      }

      // 滚动屏幕的处理 结束.

      /**
       * 加载更多记录的响应方法
       */
      AbstractPage.prototype.onLoadScrollData = function() {
        if (this.settings._trigger_load_scroll) {
          return;
        }
        this.settings._trigger_load_scroll = true;
        var callback = this.settings.onLoadScrollData;
        callback && $.isFunction(callback) && callback.apply(this);
      }
      /**
       * 刷新本页记录方法
       */
      AbstractPage.prototype.onRefreshScrollData = function() {
        if (this.settings._trigger_load_scroll) {
          return;
        }
        this.settings._trigger_load_scroll = true;
        var callback = this.settings.onRefreshScrollData;
        callback && $.isFunction(callback) && callback.apply(this);
      }

      AbstractPage.prototype.onLoadDataCompleted = function() {
        var self = this;
        self.settings._trigger_load_scroll = false;
        self.scrollFly = 0;
        self.scrollFlyOffset = 0;
      }

      AbstractPage.prototype.getSettings = function() {
        return this.settings;
      }

      /* 是否在两帧之间save-restore */
      AbstractPage.prototype.resetMatrixBetweenFrame = true;
      /* 是否在每一帧开始之前清空显示区域 */
      AbstractPage.prototype.clearRectBetweenFrame = true;
      /* 是否在两个layer之间save-restore */
      AbstractPage.prototype.resetMatrixBetweenLayer = true;

      AbstractPage.prototype.render = function(ev, data) {
        var target = this;
        var c = this.ctx2d
        var vw = this.settings.canvas.logicWidth;
        var vh = this.settings.canvas.logicHeight;
        var bw = this.settings.canvas.width;
        var bh = this.settings.canvas.height;

        var reset_flag = false;
        var reset_layer = false;
        if (this.resetMatrixBetweenFrame != false) {
          c.save();
          if (this.clearRectBetweenFrame != false) {
            c.clearRect(0, 0, vw, vh);
          }
          reset_flat = true;
        }

        $(this.mainLayers).each(function() {
          if (this.resetMatrixBetweenLayer != false) {
            c.save();
            reset_layer = true;
          }

          this.render && this.render(target, c, vw, vh, bw, bh);
          if (reset_layer) {
            c.restore();
          }
        });

        // top layer
        $(this.topLayers).each(function() {
          if (this.resetMatrixBetweenLayer != false) {
            c.save();
            reset_layer = true;
          }
          this.render && this.render(target, c, vw, vh, bw, bh);
          if (reset_layer) {
            c.restore();
          }
        });

        // control layer
        if (this.resetMatrixBetweenLayer != false) {
          c.save();
          reset_layer = true;
        }
        this.ctrlLayer && this.ctrlLayer.render
            && this.ctrlLayer.render(target, c, vw, vh, bw, bh);
        if (reset_layer) {
          c.restore();
        }

        if (reset_flag) {
          c.restore();
        }

      }

      window.Plugin = AbstractPage;
      window.AbstractPage = AbstractPage;

      return AbstractPage;

    });